package com.example.elasticsearch.studynote.demo;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpHost;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;

import java.io.IOException;
import java.util.Arrays;
import java.util.Map;

@Slf4j
public class Client {

//    @Autowired
//    private RestHighLevelClient client;

    private final RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(new HttpHost("127.0.0.1", 9200)));

    public static void main(String[] args) {
        Client client = new Client();
        try {
            client.queryTerm();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    //    @Test
    public void queryTerm() throws IOException {

        // 常规term查询
        SearchRequest searchRequest = new SearchRequest("person");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(QueryBuilders.termQuery("name.keyword", "宋青书"));
        System.out.println(searchSourceBuilder);
        searchRequest.source(searchSourceBuilder);
        SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
        System.out.println(JSONObject.toJSON(response));

        // 不带评分term查询
        SearchRequest searchRequest1 = new SearchRequest("person");
        // 这样构造的查询条件，将不进行score计算，从而提高查询效率
        searchSourceBuilder.query(QueryBuilders.constantScoreQuery(QueryBuilders.termQuery("sect.keyword", "明教")));
        searchRequest.source(searchSourceBuilder);
        SearchResponse response1 = client.search(searchRequest1, RequestOptions.DEFAULT);
        System.out.println(response1);

        // 多关键字term查询
        searchSourceBuilder.query(QueryBuilders.termsQuery("sect.keyword", Arrays.asList("明教", "武当派")));

    }

    public void termQuery() throws IOException {
        SearchRequest request = new SearchRequest();
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name.keyword", "宋青书");
        sourceBuilder.query(termQueryBuilder);

        // 查询条件
        System.out.println(sourceBuilder);

        request.source(sourceBuilder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHit[] searchHits = response.getHits().getHits();
        for (int i = 0; i < searchHits.length; i++) {
            Map<String, Object> source = searchHits[i].getSourceAsMap();
            System.out.println(source);
        }

        client.close();
    }

    public void rangeQuery() throws IOException {

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // range范围查询
        searchSourceBuilder.query(QueryBuilders.rangeQuery("age").gte(10).lte(30));

        SearchRequest request = new SearchRequest();
        request.source(searchSourceBuilder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        System.out.println(response);

    }

    public void prefixQuery() throws IOException {

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 前缀查询
        searchSourceBuilder.query(QueryBuilders.prefixQuery("sect.keyword", "武当"));


        SearchRequest request = new SearchRequest();
        request.source(searchSourceBuilder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        System.out.println(response);

    }


    public void wildcardQuery() throws IOException {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 通配符查询
        searchSourceBuilder.query(QueryBuilders.wildcardQuery("sect.keyword", "张*忌"));

        SearchRequest request = new SearchRequest();
        request.source(searchSourceBuilder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        System.out.println(response);

    }


    public void boolQuery() throws IOException {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 多条件组合查询
        searchSourceBuilder.query(QueryBuilders.boolQuery()
                .must(QueryBuilders.termQuery("sex", "女"))
                .must(QueryBuilders.termQuery("sect.keyword", "明教"))
        );

        SearchRequest request = new SearchRequest();
        request.source(searchSourceBuilder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        System.out.println(response);


    }


    public void boolQuery1() throws IOException {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        // 也可以将布尔查询单独作为一个变量，再传入searchSourceBuilder
        searchSourceBuilder.query(QueryBuilders.boolQuery()
                .must(QueryBuilders.termQuery("sex", "女"))
                .should(QueryBuilders.termQuery("address.word", "峨眉山"))
                .should(QueryBuilders.termQuery("sect.keyword", "明教"))
                .minimumShouldMatch(1)
        );

        SearchRequest request = new SearchRequest();
        request.source(searchSourceBuilder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        System.out.println(response);
    }

    public void boolQuery2() throws IOException {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        // 构建布尔查询
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
                .must(QueryBuilders.termQuery("sex", "女"))
                .must(QueryBuilders.rangeQuery("age").gte(30).lte(40))
                .mustNot(QueryBuilders.termQuery("sect.keyword", "明教"))
                .should(QueryBuilders.termQuery("address.keyword", "峨眉山"))
                .should(QueryBuilders.rangeQuery("power.keyword").gte(50).lte(80))
                .minimumShouldMatch(1);  // 设置should至少需要满足几个条件

        // 将BoolQueryBuilder构建到SearchSourceBuilder中
        searchSourceBuilder.query(boolQueryBuilder);

        SearchRequest request = new SearchRequest();
        request.source(searchSourceBuilder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        System.out.println(response);
    }

    public void filter() throws IOException {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 构建查询语句
        searchSourceBuilder.query(QueryBuilders.boolQuery()
                .filter(QueryBuilders.termQuery("sex", "男"))
        );

        SearchRequest request = new SearchRequest();
        request.source(searchSourceBuilder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        System.out.println(response);
    }

    public void filter2() throws IOException {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 构建查询语句
        searchSourceBuilder.query(QueryBuilders.boolQuery()
                .must(QueryBuilders.termQuery("sect.keyword", "明教"))
                .filter(QueryBuilders.termQuery("sex", "女"))
        );

        SearchRequest request = new SearchRequest();
        request.source(searchSourceBuilder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        System.out.println(response);
    }

    public void filter3() throws IOException {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        // 构建查询语句
        searchSourceBuilder.query(QueryBuilders.boolQuery()
                .filter(
                        QueryBuilders.boolQuery()
                                .must(QueryBuilders.termQuery("sect.keyword", "明教"))
                                .must(QueryBuilders.rangeQuery("age").gte(20).lte(35))
                                .mustNot(QueryBuilders.termQuery("sex.keyword", "女"))
                )
        );

        SearchRequest request = new SearchRequest();
        request.source(searchSourceBuilder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        System.out.println(response);
    }

    public void aggregateQuery() throws IOException {

        // 构建查询条件
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 聚合查询条件
        AggregationBuilder aggBuilder = AggregationBuilders.max("max_age").field("age");
        // 将聚合查询条件构建到SearchSourceBuilder中
        // 返回20条数据，默认只返回10条文档，对于只关心聚合结果时而言，文档本身并不重要，可以设置为size(0)，无需返回文档，只需要返回聚合结果即可
        searchSourceBuilder.aggregation(aggBuilder).size(20);

//        System.out.println("searchSourceBuilder----->" + searchSourceBuilder);

        // 请求查询es
        SearchRequest searchRequest = new SearchRequest("person");
        searchRequest.source(searchSourceBuilder);
        // 执行查询，获取SearchResponse
        SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
        System.out.println(JSONObject.toJSON(response));

    }

    public void aggregateQuery1() throws IOException {

        AggregationBuilder minBuilder = AggregationBuilders.min("min_age").field("age");
        AggregationBuilder avgBuilder = AggregationBuilders.avg("avg_age").field("age");
        AggregationBuilder sumBuilder = AggregationBuilders.sum("sum").field("age");
        AggregationBuilder countBuilder = AggregationBuilders.count("count").field("age");

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        searchSourceBuilder
                .aggregation(minBuilder)
                .aggregation(avgBuilder)
                .aggregation(sumBuilder)
                .aggregation(countBuilder);

        SearchRequest request = new SearchRequest();
        request.source(searchSourceBuilder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        System.out.println(response);

    }

    public void cardinalityQuery() throws IOException {

        // 聚合查询
        AggregationBuilder aggBuilder = AggregationBuilders.cardinality("sect_count").field("sect.keyword");

        // 构建查询条件
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 只关心聚合结果，不关心文档本身，无需返回任何文档，只需要返回聚合结果
        searchSourceBuilder.size(0);
        // 将聚合查询构建到查询条件中
        searchSourceBuilder.aggregation(aggBuilder);

        System.out.println("searchSourceBuilder----->" + searchSourceBuilder);

        // 创建某个索引的request
        SearchRequest searchRequest = new SearchRequest("person");
        searchRequest.source(searchSourceBuilder);
        // 执行查询，获取结果
        SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
        System.out.println(JSONObject.toJSON(response));
    }

    public void groupQuery() throws IOException {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.size(0);
        // terms表示分组查询，按sect分组
        AggregationBuilder aggBuilder = AggregationBuilders.terms("sect_count").field("sect.keyword");
        searchSourceBuilder.aggregation(aggBuilder);

        SearchRequest request = new SearchRequest("person");
        request.source(searchSourceBuilder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        System.out.println(response);
    }

    public void groupQuery1() throws IOException {
        SearchRequest searchRequest = new SearchRequest("person");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.size(0);
        // 先按性别分组
        AggregationBuilder sexAggBuilder = AggregationBuilders.terms("sex_count").field("sex.keyword");
        // 再按sect分组
        AggregationBuilder sectAggBuilder = AggregationBuilders.terms("sect_count").field("sect.keyword");
        // 求平均年龄
        AggregationBuilder ageAggBuilder = AggregationBuilders.avg("age_avg").field("age");

        sexAggBuilder.subAggregation(sectAggBuilder);
        sexAggBuilder.subAggregation(ageAggBuilder);


        searchSourceBuilder.aggregation(sexAggBuilder);
        System.out.println("查询语句=====================》" + searchSourceBuilder);

        searchRequest.source(searchSourceBuilder);
        SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
        System.out.println("查询结果=====================》" + JSONObject.toJSON(response));
    }

    public void queryAgg() throws IOException {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 聚合查询条件
        AggregationBuilder maxBuilder = AggregationBuilders.max("max_age").field("age");
        // 等值查询
        searchSourceBuilder.query(QueryBuilders.termQuery("sect.keyword", "明教"));
        // 在上一步查询结果中进行聚合
        searchSourceBuilder.aggregation(maxBuilder);

        SearchRequest request = new SearchRequest("person");
        request.source(searchSourceBuilder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        System.out.println(response);
    }


    public void complicatedQuery() throws IOException {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.size(0);
        // 查询0-20，21-40，41-60，61以上的各有多少人
        AggregationBuilder ageAggBuilder = AggregationBuilders.range("person_count").field("age")
                .addRange(20, 40)
                .addRange(40, 60)
                .addRange(60, 120);

        searchSourceBuilder.aggregation(ageAggBuilder);
        System.out.println("查询语句=====================》" + searchSourceBuilder);

        SearchRequest searchRequest = new SearchRequest("person");
        searchRequest.source(searchSourceBuilder);
        SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
        System.out.println("查询结果=====================》" + JSONObject.toJSON(response));
    }

    public void highLightQuery() throws IOException {

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        // 查询数据
        searchSourceBuilder.query(QueryBuilders.matchQuery("name", "宋青书"));

        HighlightBuilder highlightBuilder = new HighlightBuilder();
        // 加上红色字体标签表示高亮
        highlightBuilder.field("name", 10)
                .preTags("<font color='red'>")
                .postTags("</font>");

        // 高亮查询
        searchSourceBuilder.highlighter(highlightBuilder);

        System.out.println(searchSourceBuilder);

        SearchRequest request = new SearchRequest();
        request.source(searchSourceBuilder);
        SearchResponse resp = client.search(request, RequestOptions.DEFAULT);

        System.out.println(resp);

        // 获取高亮数据，输出
        for (SearchHit hit : resp.getHits().getHits()) {
            System.out.println(hit.getHighlightFields().get("name"));
        }

        client.close();
    }


}
